package cn.edu.xmu.orderpayment.order.service;

import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.orderpayment.order.constants.Constants;
import cn.edu.xmu.orderpayment.order.dao.OrderDao;

import cn.edu.xmu.orderpayment.order.microservice.retvo.*;
import cn.edu.xmu.orderpayment.order.microservice.service.*;
import cn.edu.xmu.orderpayment.order.microservice.vo.*;
import cn.edu.xmu.orderpayment.order.model.bo.Order;
import cn.edu.xmu.orderpayment.order.model.bo.OrderItem;
import cn.edu.xmu.orderpayment.order.model.enums.*;
import cn.edu.xmu.orderpayment.order.model.po.OrderItemPo;
import cn.edu.xmu.orderpayment.order.model.po.OrderPo;
import cn.edu.xmu.orderpayment.order.model.retvo.*;
import cn.edu.xmu.orderpayment.order.model.vo.*;
import cn.edu.xmu.orderpayment.order.mq.RocketMQService;
import cn.edu.xmu.privilegegateway.annotation.util.InternalReturnObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.edu.xmu.oomall.core.util.Common.getListRetVo;
import static cn.edu.xmu.oomall.core.util.ReturnNo.*;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.*;

/**
 * @author YuJie
 * @date 2021-12-02
 */
@Service
@Component
public class OrderService {

    private Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    private OrderDao orderDao;


    @Autowired
    private PayService payService;

    @Autowired
    private FreightService freightService;

    @Autowired
    private ShopService shopService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private CouponService couponService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private RocketMQService rocketMQService;


    /**
     * 获取订单所有状态 写死在BO中
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getAllState() {
        List<Map<String, Object>> stateList = new ArrayList<>();
        for (OrderState state : OrderState.values()) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("code", state.getCode());
            temp.put("name", state.getDescription());
            stateList.add(temp);
        }
        return new ReturnObject(stateList);
    }


    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderByPid(Long pid) {

        ReturnObject returnObject = orderDao.getOrderByPid(pid);
        if (returnObject.getData() == null) {
            return returnObject;
        } else {
            return getListRetVo(returnObject, SimpleOrderInfoRetVo.class);
        }
    }

    /**
     * 买家查询自己的订单概要
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject searchMyselfOrders(Long loginUserId, String orderSn, ZonedDateTime beginTime,
                                           ZonedDateTime endTime, Integer state, Integer page, Integer pageSize) {
        return orderDao.searchMyselfOrders(loginUserId, orderSn, beginTime, endTime, state, page, pageSize);
    }


    /**
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject createMyselfOrder(NewOrderVo vo, Long userId, String userName) {


        RegionRetVo regionRetVo = freightService.getRegionById(vo.getRegionId()).getData();
        if (regionRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "地区不存在");
        }
        if (regionRetVo.getState() == RegionState.STOPPED) {
            return new ReturnObject(FREIGHT_REGION_NOTREACH, "该地区停发");
        }
        if (regionRetVo.getState() == RegionState.CANCELED) {
            return new ReturnObject(FREIGHT_REGIONOBSOLETE, "该地区已废弃");
        }
        if (vo.getAdvancesaleId() != null && vo.getGrouponId() != null) {
            return new ReturnObject(ACTIVITY_NOTFOUND, "无法同时参与团购和预售");
        }
        if (vo.getAdvancesaleId() != null) {
            InternalReturnObject<AdvanceSaleRetVo> actRet = activityService.getAdvanceActById(vo.getAdvancesaleId());
            if (actRet == null || actRet.getData() == null) {
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "预售活动不存在");
            }
            if (actRet.getData().getBeginTime().isAfter(ZonedDateTime.now())) {
                return new ReturnObject(STATENOTALLOW, "预售活动未开始");
            }
            List<OrderItemVo> itemVoList = vo.getOrderItems();
            if (itemVoList.size() > 1) return new ReturnObject<>(GOODS_STOCK_SHORTAGE, "预售活动只允许下单一个商品");
            return internalCreateOrder(vo, userId, userName, actRet.getData(), null);
        } else if (vo.getGrouponId() != null) {
            InternalReturnObject<GrouponActRetVo> actRet = activityService.getGrouponActById(vo.getGrouponId());
            if (actRet == null || actRet.getData() == null) {
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "团购活动不存在");
            }
            if (actRet.getData().getState() != ActState.ONLINE) return new ReturnObject<>(STATENOTALLOW, "团购活动没有上线");
            List<OrderItemVo> itemVoList = vo.getOrderItems();
            if (itemVoList.size() > 1) return new ReturnObject<>(GOODS_STOCK_SHORTAGE, "团购活动只允许下单一个商品");
            return internalCreateOrder(vo, userId, userName, null, actRet.getData());
        } else {
            return internalCreateOrder(vo, userId, userName, null, null);
        }
    }

    private ReturnObject internalCreateOrder(NewOrderVo vo, Long userId, String userName, AdvanceSaleRetVo advanceActRetVo, GrouponActRetVo grouponActRetVo) {

        List<OrderItemVo> itemVoList = vo.getOrderItems();

        List<ProductRetVo> productRetVoList = new ArrayList<>();
        List<OnSaleRetVo> onSaleRetVoList = new ArrayList<>();
        List<OrderItem> orderItemList = new ArrayList<>();
        // 优惠券set 可能几个item用同一个coupon
        Set<Long> couponSet = new HashSet<>();
        // 算优惠和运费列表
        List<FreightCalVo> freightCalVoList = new ArrayList<>();
        List<CouponCalVo> couponCalVoList = new ArrayList<>();

        Long allPrice = 0L;
        for (OrderItemVo itemVo : itemVoList) {
            InternalReturnObject<ProductRetVo> productRet = goodsService.getProductById(itemVo.getProductId());
            InternalReturnObject<OnSaleRetVo> onSaleRet = goodsService.getOnSaleById(itemVo.getOnsaleId());
            // check product and onsale valid
            ReturnObject errorReturn = checkProductOnSale(productRet, onSaleRet);
            if (errorReturn.getCode() != OK) return errorReturn;
            if (itemVo.getCouponId() != null) {
                // check couponAct valid
                ReturnObject<Object> couponErrorReturn = checkCoupon(itemVo);
                if (couponErrorReturn.getCode() != OK) return couponErrorReturn;
            }
            productRetVoList.add(productRet.getData());
            onSaleRetVoList.add(onSaleRet.getData());

            // 优惠计算列表加入
            CouponCalVo couponCalVo = new CouponCalVo(itemVo.getProductId(), itemVo.getOnsaleId(), itemVo.getQuantity(), onSaleRet.getData().getPrice(), itemVo.getCouponActivityId());
            couponCalVoList.add(couponCalVo);

            // 运费计算列表加入
            FreightCalVo freightCalVo = new FreightCalVo(productRet.getData(), itemVo.getQuantity());
            freightCalVoList.add(freightCalVo);

            // OrderItem列表加入
            OrderItem orderItem = cloneVo(itemVo, OrderItem.class);
            orderItem.init();
            orderItem.setShopId(productRet.getData().getShopId());
            orderItem.setPrice(onSaleRet.getData().getPrice());
            orderItem.setName(productRet.getData().getName());
            setPoCreatedFields(orderItem, userId, userName);
            orderItemList.add(orderItem);

            // 算出总金额
            allPrice += orderItem.getPrice() * orderItem.getQuantity();

            // 优惠券set加入
            if (orderItem.getCouponId() != null) couponSet.add(orderItem.getCouponId());

        }

        // 预扣库存
        for (int i = 0; i < itemVoList.size(); i++) {
            OrderItemVo itemVo = itemVoList.get(i);
            goodsService.decreaseOnSale(itemVo.getOnsaleId(), new QuantityVo(itemVo.getQuantity()));
        }


        // 调用微服务计算优惠列表
        InternalReturnObject<List<CouponCalRetVo>> couponCalRetVoListRet = couponService.calculateDiscount(couponCalVoList);
        List<CouponCalRetVo> couponCalRetVoList = couponCalRetVoListRet.getData();
        // 调用微服务计算邮费
        InternalReturnObject<FreightCalRetVo> freightCalRet = freightService.calFreight(vo.getRegionId(), freightCalVoList);
        FreightCalRetVo freightCalRetVo = freightCalRet.getData();
        Long express = freightCalRetVo.getFreightPrice();

        Long allPoint = 0L;
        if (vo.getPoint() != null) allPoint = vo.getPoint();


        // 扣积点 如果是预售，则在定金扣除  如果point > 定金 则只扣定金的积点
        if (advanceActRetVo != null) {
            Long advancePrice = advanceActRetVo.getAdvancePayPrice();
            if (allPoint > advancePrice + express) {
                allPoint = advancePrice + express;
            }
        } else {
            if (allPoint > allPrice + express) {
                allPoint = allPrice + express;
            }
        }

        // 使用积点 获得真实使用的积点数
        InternalReturnObject<PointUseRetVo> pointUseRetVoInternalReturnObject = customerService.usePoint(userId, allPoint);
        allPoint = pointUseRetVoInternalReturnObject.getData().getPoint();

        Long resPoints = allPoint > express ? allPoint - express : 0;
        // 计算总共的优惠价格
        Long allDiscount = 0L;
        for (int i = 0; i < orderItemList.size(); i++) {
            for (int j = 0; j < couponCalRetVoList.size(); j++) {
                if (couponCalRetVoList.get(j).getProductId().equals(orderItemList.get(i).getProductId())) {
                    orderItemList.get(i).setDiscountPrice(couponCalRetVoList.get(j).getDiscountPrice());
                    allDiscount += couponCalRetVoList.get(j).getDiscountPrice() * orderItemList.get(i).getQuantity();
                    orderItemList.get(i).setPoint(Math.round(1.0 * resPoints * orderItemList.get(i).getPrice() * orderItemList.get(i).getQuantity() / allPrice));
                    break;
                }
            }
        }

        allDiscount = Math.round(1.0 * allDiscount / 10);

        // 防止优惠券重复使用
        for (Long couponId : couponSet) {
            customerService.useCoupon(couponId);
        }

        // 新建订单orderBO
        Order finalOrder = cloneVo(vo, Order.class);
        finalOrder.init();
        finalOrder.setShopId(orderItemList.get(0).getShopId());
        finalOrder.setCustomerId(userId);
        finalOrder.setDiscountPrice(allDiscount);
        finalOrder.setExpressFee(freightCalRetVo.getFreightPrice());
        finalOrder.setShopId(0L);
        finalOrder.setOriginPrice(allPrice);
        finalOrder.setPoint(allPoint);
        finalOrder.setOrderItems(orderItemList);
        setPoCreatedFields(finalOrder, userId, userName);
        if (advanceActRetVo == null) {
            finalOrder.setAdvancesaleId(0L);
        }
        if (grouponActRetVo == null) {
            finalOrder.setGrouponId(0L);
        }

        // 发送order message 由消费者处理存进数据库
        rocketMQService.sendOrderMessage(finalOrder);


        // 如果是预售 返回 定金和尾款两个支付信息
        // 积点算在定金 运费算在尾款
        if (advanceActRetVo != null) {
            NewOrderRetVo retVo1 = new NewOrderRetVo();
            retVo1.setOrderSn(finalOrder.getOrderSn() + "-D");
            retVo1.setBeginTime(LocalDateTime.now().atZone(ZoneId.systemDefault()));
            retVo1.setEndTime(advanceActRetVo.getPayTime().withZoneSameInstant(ZoneId.systemDefault()));
            retVo1.setDescr(finalOrder.getOrderSn() + " - 预售定金");
            retVo1.setDocumentType(DocumentType.ADVANCEPRICE);
            retVo1.setAmount(advanceActRetVo.getAdvancePayPrice() - allPoint);

            NewOrderRetVo retVo2 = new NewOrderRetVo();
            retVo2.setOrderSn(finalOrder.getOrderSn() + "-W");
            retVo2.setBeginTime(advanceActRetVo.getPayTime().withZoneSameInstant(ZoneId.systemDefault()));
            retVo2.setDescr(finalOrder.getOrderSn() + " - 预售尾款");
            retVo2.setDocumentType(DocumentType.RESTPRICE);
            retVo2.setAmount(allPrice - advanceActRetVo.getAdvancePayPrice() + finalOrder.getExpressFee());
            // 发送订单支付确认消息 若到时未支付 则取消订单 释放库存
            rocketMQService.sendOrderCheckMessage(finalOrder.getOrderSn());
            return new ReturnObject<>(Stream.of(retVo1, retVo2).collect(Collectors.toList()));

        }

        // 建立返回的vo
        NewOrderRetVo retVo = new NewOrderRetVo();
        retVo.setOrderSn(finalOrder.getOrderSn());
        retVo.setBeginTime(LocalDateTime.now().atZone(ZoneId.systemDefault()));
        retVo.setEndTime(LocalDateTime.now().plusMinutes(30).atZone(ZoneId.systemDefault()));
        if (grouponActRetVo != null) {
            retVo.setDescr(finalOrder.getOrderSn() + " - 新团购订单");
        } else {
            retVo.setDescr(finalOrder.getOrderSn() + " - 新订单");
        }
        retVo.setDocumentType(DocumentType.ORDER);
        retVo.setAmount(finalOrder.getOriginPrice() - finalOrder.getDiscountPrice() + finalOrder.getExpressFee() - finalOrder.getPoint());

        // 发送定时消息，三十分钟没支付则取消
        rocketMQService.sendOrderCheckMessage(finalOrder.getOrderSn());
        return new ReturnObject<>(Stream.of(retVo).collect(Collectors.toList()));
    }

    private ReturnObject<Object> checkCoupon(OrderItemVo itemVo) {
        InternalReturnObject couponVoRet = customerService.getCouponById(itemVo.getCouponId());
        if (couponVoRet.getData() == null) return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "该优惠券不存在");
        CouponRetVoForPayment couponRetVoForPayment = (CouponRetVoForPayment) couponVoRet.getData();
        if (couponRetVoForPayment.getState() != CouponState.RECEIVED.getCode().byteValue())
            return new ReturnObject<>(COUPON_END, "优惠券不可用");
        if (couponRetVoForPayment.getBeginTime().isAfter(ZonedDateTime.now()))
            return new ReturnObject<>(STATENOTALLOW, "优惠券使用时间未到");
        if (couponRetVoForPayment.getEndTime().isBefore(ZonedDateTime.now()))
            return new ReturnObject<>(STATENOTALLOW, "优惠券使用时间已到");
        return new ReturnObject<>();
    }

    private ReturnObject checkProductOnSale(InternalReturnObject<ProductRetVo> productRet, InternalReturnObject<OnSaleRetVo> onSaleRet) {
        if (productRet.getData() == null) return new ReturnObject(RESOURCE_ID_NOTEXIST, "该商品不存在");
        if (productRet.getData().getState() != 2) return new ReturnObject(STATENOTALLOW, "该货品未上架");
        if (onSaleRet.getData() == null) return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该价格销售不存在");
        if (onSaleRet.getData().getState() != ActState.ONLINE.getCode().byteValue())
            return new ReturnObject(STATENOTALLOW, "该商品未上线");
        if (!onSaleRet.getData().getProduct().getId().equals(productRet.getData().getId()))
            return new ReturnObject<>(RESOURCE_ID_OUTSCOPE, "不是该销售的货品");
        return new ReturnObject();
    }


    /**
     * 用户查询自己订单明细
     * 传入userId和订单id匹配校验
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getMyselfOrderDetail(Long loginUserId, Long id) {


        ReturnObject returnObject = orderDao.getOrder(id);
        if (returnObject.getData() == null) return returnObject;
        Order order = (Order) returnObject.getData();
        if (order.getBeDeleted().equals(Byte.valueOf("1"))) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该id订单不存在");
        }

        if (!order.getCustomerId().equals(loginUserId)) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于此用户");
        }

        InternalReturnObject customerRetObj = customerService.getCustomerById(order.getCustomerId());
        SimpleCustomerRetVo simpleCustomerRetVo = (SimpleCustomerRetVo) customerRetObj.getData();
        if (simpleCustomerRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该用户不存在");
        }

        ShopRetVo shopRetVo = new ShopRetVo(0L, null);
        if (order.getShopId() != 0) {
            InternalReturnObject shopRetObj = shopService.getShopById(order.getShopId());
            shopRetVo = (ShopRetVo) shopRetObj.getData();
        }

        ReturnObject<List> orderItemsRetObj = orderDao.getOrderItemsByOrderId(id);
        List<SimpleOrderItemRetVo> list = new ArrayList<>();
        if (!(orderItemsRetObj.getData() == null || orderItemsRetObj.getData().size() == 0)) {
            list.addAll((List<SimpleOrderItemRetVo>) getListRetVo(orderItemsRetObj, SimpleOrderItemRetVo.class).getData());
        }

        OrderInfoRetVo orderInfoRetVo = cloneVo(order, OrderInfoRetVo.class);
        orderInfoRetVo.setCustomer(simpleCustomerRetVo);
        orderInfoRetVo.setShop(shopRetVo);
        orderInfoRetVo.setOrderItem(list);

        return new ReturnObject(orderInfoRetVo);
    }

    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getShopOrderDetail(Long shopId, Long id) {

        ReturnObject returnObject = orderDao.getOrder(id);
        Order order = (Order) returnObject.getData();
        if (order == null) {
            return returnObject;
        }

        if (!order.getShopId().equals(shopId)) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于此商户");
        }

        InternalReturnObject customerRetObj = customerService.getCustomerById(order.getCustomerId());
        SimpleCustomerRetVo simpleCustomerRetVo = (SimpleCustomerRetVo) customerRetObj.getData();
        if (simpleCustomerRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该订单对应用户不存在");
        }

        InternalReturnObject shopRetObj = shopService.getShopById(order.getShopId());
        ShopRetVo shopRetVo = (ShopRetVo) shopRetObj.getData();
        if (shopRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该商户不存在");
        }

        ReturnObject orderItemsRetObj = orderDao.getOrderItemsByOrderId(id);
        if (orderItemsRetObj.getData() == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "订单明细不存在");
        }
        List<SimpleOrderItemRetVo> list = (List<SimpleOrderItemRetVo>) getListRetVo(orderItemsRetObj, SimpleOrderItemRetVo.class).getData();

        OrderInfoRetVo orderInfoRetVo = cloneVo(order, OrderInfoRetVo.class);
        orderInfoRetVo.setCustomer(simpleCustomerRetVo);
        orderInfoRetVo.setShop(shopRetVo);
        orderInfoRetVo.setOrderItem(list);

        return new ReturnObject(orderInfoRetVo);
    }


    /**
     * 用户修改未发货订单的收货信息
     * 传入userId匹配校验
     * 传入要修改的收货信息
     *
     * @return
     * @author wang xusheng
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject modifyMyselfOrder(Long id, Order orderBo, Long loginUserId, String loginUserName) {
        //根据订单id获得订单
        ReturnObject ret = orderDao.getOrder(id);
        if (ret.getCode().equals(RESOURCE_ID_NOTEXIST)) {
            return ret;
        }
        Order order = (Order) ret.getData();

        if (!loginUserId.equals(order.getCustomerId())) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "不能修改其他用户的订单");
        }
        // 判断order是否未发货
        OrderState orderState = order.getState();
        if (orderState.equals(OrderState.HAS_DELIVERED) || orderState.equals(OrderState.HAS_CANCELED) || orderState.equals(OrderState.COMPLETED)) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "当前状态禁止此操作");
        }
        orderBo.setId(id);
        //若未发货则进行修改,传入要修改的Bo
        ReturnObject res = orderDao.updateOrder(orderBo, loginUserId, loginUserName);
        return res;
    }

    /**
     * 买家逻辑删除本人名下订单
     * 存在性检验：
     * 订单id：不存在则不处理该订单，并返回错误
     * <p>
     * 合法性验证：
     * 用户id跟购买者是不是一样，不一样返回507错误
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject deleteUserSelfOrder(Long userId, String userName, Long orderId) {
        ReturnObject orderRet = orderDao.getOrder(orderId);
        if (orderRet.getData() == null) {
            return orderRet;
        }
        Order order = (Order) orderRet.getData();
        if (!order.getCustomerId().equals(userId)) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        }

        if (!(order.getState() == OrderState.COMPLETED || order.getState() == OrderState.HAS_CANCELED)) {
            return new ReturnObject<>(STATENOTALLOW);
        }

        order.setBeDeleted((byte) 1);
        return orderDao.updateOrder(order, userId, userName);
    }

    /**
     * 买家取消本人名下订单
     * 存在性检验：
     * 订单id：不存在则不处理该订单，并返回错误
     * <p>
     * 合法性验证：
     * 用户id跟购买者是不是一样，不一样返回507错误
     *
     * @return
     * @creator liuyunlong
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject cancelUserSelfOrder(Long orderId, Long userId, String userName) {
        //看看是不是本用户的订单
        ReturnObject returnObject = orderDao.getOrder(orderId);
        if (returnObject.getData() == null) return returnObject;
        Order order = (Order) returnObject.getData();
        if (!Objects.equals(userId, order.getCustomerId())) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        }
        return internalCancelOrder(userId, userName, order);
    }

    /**
     * 买家标记确认收货
     * 存在性检验：
     * 订单id：不存在则不处理该订单，并返回错误
     * <p>
     * 合法性验证：
     * 用户id跟购买者是不是一样，不一样返回507错误
     *
     * @return
     * @author wang xusheng
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject confirmUserSelfOrder(Long userId, Long orderId, String loginName) {
        ReturnObject ret = orderDao.getOrder(orderId);
        if (ret.getData() == null) {
            return ret;
        }
        Order order = (Order) ret.getData();
        //看看是不是本用户的订单
        if (!order.getCustomerId().equals(userId)) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "不能修改其他用户的订单");
        }
        //查看订单状态
        if (order.getState() != OrderState.HAS_DELIVERED) return new ReturnObject(STATENOTALLOW, "该状态无法收货");
        //若未发货则进行修改,传入要修改的Bo
        order.setState(OrderState.COMPLETED);
        ReturnObject res = orderDao.updateOrder(order, userId, loginName);
        return res;
    }

    /**
     * 店家查询商户所有订单 (概要)
     * 存在性检验：
     * 商铺id：不存在则返回错误
     * 已经被客户逻辑删除的订单也一并返回
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getShopOrder(Long shopId, Long customerId, String orderSn,
                                     ZonedDateTime beginTime, ZonedDateTime endTime, Integer page, Integer pageSize) {
        return orderDao.searchShopOrders(shopId, customerId, orderSn, beginTime, endTime, page, pageSize);
    }

    /**
     * 店家修改订单 (留言)
     * 存在性检验：
     * 商铺id：不存在则返回错误
     * 合法性检验：
     * 订单不是店家的不予修改
     *
     * @return
     * @author wang xusheng
     * TODO 验证登录用户只能操作本商铺订单
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject shopsModifyOrder(Long loginId, Long shopId, Long id, String message, String loginName) {
        //查看有没有商铺
        InternalReturnObject ret = shopService.getShopById(shopId);
        if (ret.getData() == null) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST, "店铺不存在");
        }
        //查看有没有订单，是不是这个店铺的
        ReturnObject retOrder = orderDao.getOrder(id);
        if (retOrder.getData() == null) {
            return retOrder;
        }
        Order order = (Order) retOrder.getData();
        if (!order.getShopId().equals(shopId)) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "不能修改其他店铺订单");
        }
        order.setMessage(message);
        ReturnObject res = orderDao.updateOrder(order, loginId, loginName);
        return res;
    }


    /**
     * 商家标记订单发货，需要登录
     * 商家可以用此 API 将一个状态为待发货的订单改为待收货，并记录运单信息。
     * 验证shopId和id,传入发货资讯
     *
     * @return
     * @creator wang xusheng
     * @author wang xusheng
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject deliverOrder(Long loginUserId, Long shopId, Long id, String freightSn, String loginName) {
        //查看有没有商铺
        InternalReturnObject<ShopRetVo> retShop = shopService.getShopById(shopId);
        if (retShop.getData() == null) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST, "店铺不存在");
        }
        //查看有没有订单，是不是这个店铺的
        ReturnObject retOrder = orderDao.getOrder(id);
        if (retOrder.getData() == null) return retOrder;
        Order order = (Order) retOrder.getData();
        if (!order.getShopId().equals(shopId)) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "不能修改其他店铺订单");
        }
//        if(!order.getState().equals(OrderState.WAIT_DELIVER)){
//            return new ReturnObject(STATENOTALLOW,"当前状态禁止此操作");
//        }
        order.setState(OrderState.HAS_DELIVERED);
        order.setShipmentSn(freightSn);
        order.setConfirmTime(LocalDateTime.now());
        ReturnObject res = orderDao.updateOrder(order, loginUserId, loginName);
        return res;
    }


    /**
     * 需要登录，传入商店id和订单id
     * 需根据团购规则退款
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject confirmGroupOnOrder(Long userId, String userName, Long shopId, Long orderId) {

        ReturnObject orderInDatebase = orderDao.getOrder(orderId);
        if (orderInDatebase.getData() == null) {
            //返回数据库的错误
            return orderInDatebase;
        }

        Order order = (Order) orderInDatebase.getData();
        if (!order.getCustomerId().equals(userId) //用户对不上
                || !order.getShopId().equals(shopId)  //shopId对不上
                || order.getGrouponId() == null   //不是团购
        ) {
            return new ReturnObject(ReturnNo.STATENOTALLOW);  //TODO 不知道返回什么
        }
        InternalReturnObject<GrouponActRetVo> activityReturnObject = activityService.getGrouponActById(order.getGrouponId());
        if (activityReturnObject.getData() == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST);
        }
        GrouponActRetVo grouponActRetVo = activityReturnObject.getData();
        //判断是不是上线的团购活动
        if (grouponActRetVo.getState() != ActState.ONLINE) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "此团购活动不是上线状态");
        }
        List<GroupOnStrategyRetVo> strategyList = grouponActRetVo.getStrategy();

        ReturnObject returnObject = orderDao.getOrderByGrouponActivityId(grouponActRetVo.getId());
        if (returnObject.getData() == null) {
            return returnObject;   //
        }
        List<OrderPo> orderPoList = (List<OrderPo>) returnObject.getData();

        int count = orderPoList.size();
        int strategyCount = orderPoList.size();
        int percentage = 1000;
        for (GroupOnStrategyRetVo groupOnStrategyRetVo : strategyList) {
            if (count >= groupOnStrategyRetVo.getQuantity()) {
                percentage = groupOnStrategyRetVo.getPercentage();
            }
        }
        Long refundAmount = order.getOriginPrice();
        if (percentage != 1000) {
            refundAmount = order.getOriginPrice() - order.getOriginPrice() * percentage / 1000;
        }

        payService.refund(order.getOrderSn(), refundAmount, (byte) 0, "团购确认根据规则退款");


        order.setState(OrderState.HAS_PAYED);

        return orderDao.updateOrder(order, userId, userName);
    }

    /**
     * 需要登录，传入商店id和订单id
     * 需全额退款（包括预售订单的订金）
     *
     * @return
     * @creator liuyunlong
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject cancelOrder(Long shopId, Long id, Long userId, String userName) {
        ReturnObject ret1 = orderDao.getOrder(id);
        if (ret1.getData() == null) {
            return ret1;
        }
        Order order = (Order) ret1.getData();
        if (shopId != 0L && !Objects.equals(order.getShopId(), shopId)) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "本订单不属于该商铺");
        }
        return internalCancelOrder(userId, userName, order);
    }

    private ReturnObject internalCancelOrder(Long userId, String userName, Order order) {

        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Constants.servletRequestAttributes = servletRequestAttributes;

        List<Order> subOrders = new ArrayList();
        List<OrderItem> orderItemList = new ArrayList<>();
        if (order.getPid() != 0) {
            ReturnObject ret2 = orderDao.getOrder(order.getPid());
            if (ret2.getData() == null) {
                return ret2;
            }
            order = cloneVo(ret2.getData(), Order.class);
            ReturnObject ret3 = orderDao.getOrderByPid(order.getId());
            List<OrderPo> orderPos = (List<OrderPo>) ret3.getData();
            for (OrderPo orderPo : orderPos) {
                Order subOrder = cloneVo(orderPo, Order.class);
                subOrders.add(subOrder);
            }
        }
        // 已完成不能取消
        if (order.getState() == OrderState.COMPLETED) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "当前状态禁止此操作");
        }
        // 新订单不退款
        if (order.getState() == OrderState.NEW_ORDER || order.getState() == OrderState.WAIT_REST) {
            order.setState(OrderState.HAS_CANCELED);
            orderDao.updateOrder(order, userId, userName);
            return new ReturnObject<>();
        }

        if (subOrders.size() == 0) {
            ReturnObject<List> orderItemListRet = orderDao.getOrderItemsByOrderId(order.getId());
            orderItemList = orderItemListRet.getData();
        } else {
            for (Order subOrder : subOrders) {
                ReturnObject<List> orderItemListRet = orderDao.getOrderItemsByOrderId(subOrder.getId());
                List<OrderItemPo> tempList = orderItemListRet.getData();
                for (OrderItemPo orderItem : tempList) {
                    orderItemList.add(cloneVo(orderItem, OrderItem.class));
                }
            }
        }

        // 预售退两笔
        if (order.getAdvancesaleId() != null && order.getAdvancesaleId() != 0) {
            InternalReturnObject<AdvanceSaleRetVo> actVoRet = activityService.getAdvanceActById(order.getAdvancesaleId());
            if (actVoRet.getData() != null) {

                AdvanceSaleRetVo act = actVoRet.getData();
                Long restAmount = order.getOriginPrice() - order.getExpressFee();
                String sn = order.getOrderSn();
                payService.refundAll(sn + "-D", (byte) 0, "取消订单退定金");
                payService.refund(sn + "-W", restAmount, (byte) 0, "取消订单退尾款");

                order.setState(OrderState.WAIT_REFUND);
                orderDao.updateOrder(order, userId, userName);
                return new ReturnObject<>();
            }
            return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "该预售活动不存在");
        }
        // 普通退全款
        Long finalAmount = order.getOriginPrice() - order.getPoint() - order.getDiscountPrice() + order.getExpressFee();
        String sn = order.getOrderSn();

        payService.refund(order.getOrderSn(), finalAmount, (byte) 0, "取消订单退全款");
        order.setState(OrderState.WAIT_REFUND);
        orderDao.updateOrder(order, userId, userName);
        if (subOrders.size() != 0) {
            for (Order subOrder : subOrders) {
                subOrder.setState(OrderState.WAIT_REFUND);
                orderDao.updateOrder(subOrder, userId, userName);
            }
        }
        return new ReturnObject<>();
    }

    /**
     * 此类订单是用于售后换货或者是售后支付
     * 如果是售后换货的新建状态是待发货，价格为0"
     * 如果是售后支付则新建状态时待付款
     * 需要传入orderInfo，包括订单信息、商品信息以及是否由顾客支付
     *
     * @return
     * @creator wang xusheng
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject createAfterSaleOrder(NewAfterSaleOrderVo newAfterSaleOrderVo, Long loginUserId, String loginName) {
        RegionRetVo regionRetVo = freightService.getRegionById(newAfterSaleOrderVo.getRegionId()).getData();
        if (regionRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "地区不存在");
        }
        if (regionRetVo.getState() == RegionState.STOPPED) {
            return new ReturnObject(FREIGHT_REGION_NOTREACH, "该地区停发");
        }
        if (regionRetVo.getState() == RegionState.CANCELED) {
            return new ReturnObject(FREIGHT_REGIONOBSOLETE, "该地区已废弃");
        }


        InternalReturnObject<SimpleCustomerRetVo> simpleCustomerRetVoInternalReturnObject =
                customerService.getCustomerById(newAfterSaleOrderVo.getCustomerId());
        if (simpleCustomerRetVoInternalReturnObject.getData() == null)
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该顾客不存在");

        List<AfterSaleOrderItemVo> afterSaleOrderItemVoList = newAfterSaleOrderVo.getOrderItems();
        InternalReturnObject<ShopRetVo> shopRetVoInternalReturnObject = null;

        Long shopId = null;
        List<OrderItem> orderItemList = new ArrayList<>();
        for (AfterSaleOrderItemVo itemVo : afterSaleOrderItemVoList) {
            OrderItem orderItem = cloneVo(itemVo, OrderItem.class);
            orderItem.init();

            InternalReturnObject<ProductRetVo> productRet = goodsService.getProductById(itemVo.getProductId());
            if (productRet.getData() == null) return new ReturnObject(RESOURCE_ID_NOTEXIST, "货品不存在");
            InternalReturnObject<OnSaleRetVo> onSaleRetVoInternalReturnObject = goodsService.getOnSaleById(itemVo.getOnsaleId());
            if (onSaleRetVoInternalReturnObject.getData() == null)
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "该货品没有销售");
            ProductRetVo productRetVo = (ProductRetVo) productRet.getData();
            shopId = productRetVo.getShopId();
            shopRetVoInternalReturnObject = shopService.getShopById(shopId);
            if (shopRetVoInternalReturnObject.getData() == null) return new ReturnObject(RESOURCE_ID_NOTEXIST, "店铺不存在");
            orderItem.setShopId(shopId);
            orderItem.setName(productRetVo.getName());
            setPoCreatedFields(orderItem, loginUserId, loginName);
            orderItemList.add(orderItem);
        }
        Order order = cloneVo(newAfterSaleOrderVo, Order.class);
        order.init();
        order.setShopId(shopId);
        setPoCreatedFields(order, loginUserId, loginName);

        ReturnObject<OrderPo> ret = orderDao.createOrder(order);
        List<SimpleOrderItemRetVo> simpleOrderItemRetVoList = new ArrayList<>();
        for (OrderItem item : orderItemList) {
            item.setOrderId(ret.getData().getId());
            ReturnObject<OrderItemPo> poRet = orderDao.createOrderItem(item);
            SimpleOrderItemRetVo simpleOrderItemRetVo = cloneVo(poRet.getData(), SimpleOrderItemRetVo.class);
            simpleOrderItemRetVoList.add(simpleOrderItemRetVo);
        }

        OrderInfoRetVo orderInfoRetVo = cloneVo(ret.getData(), OrderInfoRetVo.class);
        orderInfoRetVo.setOrderItem(simpleOrderItemRetVoList);

        orderInfoRetVo.setCustomer(simpleCustomerRetVoInternalReturnObject.getData());
        orderInfoRetVo.setShop(shopRetVoInternalReturnObject.getData());

        return new ReturnObject<>(orderInfoRetVo);
    }

    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderPayInfo(Long id, Long userId) {
        ReturnObject<Order> ret = orderDao.getOrder(id);
        if (ret.getData() == null) return new ReturnObject(RESOURCE_ID_NOTEXIST, "该订单不存在");
        Order order = ret.getData();
        if (!Objects.equals(order.getCustomerId(), userId)) return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        String orderSn = order.getOrderSn();
        if (order.getState() == OrderState.WAIT_REST) {
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject = payService.getPaymentByDocumentId(orderSn + "-D");
            if (paymentRetVoInternalReturnObject.getData() == null
                    || paymentRetVoInternalReturnObject.getData().size() == 0)
                return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "没有支付单");
            return new ReturnObject(paymentRetVoInternalReturnObject.getData());
        }
        else if(order.getAdvancesaleId()!=null&&!order.getAdvancesaleId().equals(0L)){
            List<PaymentRetVo> paymentRetVoList=new ArrayList<>();
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject=payService.getPaymentByDocumentId(orderSn+"-D");
            if(paymentRetVoInternalReturnObject.getData()==null)return new ReturnObject<>(RESOURCE_ID_NOTEXIST,"没有支付单");
            paymentRetVoList.addAll(paymentRetVoInternalReturnObject.getData());
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject1 = payService.getPaymentByDocumentId(orderSn + "-W");
            if (paymentRetVoInternalReturnObject1.getData() == null)
                return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "没有支付单");
            paymentRetVoList.addAll(paymentRetVoInternalReturnObject.getData());
            return new ReturnObject(paymentRetVoList);
        } else {
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject = payService.getPaymentByDocumentId(orderSn);
            if (paymentRetVoInternalReturnObject.getData() == null)
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "该支付单不存在");
            return new ReturnObject(paymentRetVoInternalReturnObject.getData());
        }
    }


    /**
     * 用户根据订单id查询订单的退款信息
     * 需要登录，返回退款单信息
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderRefundInfo(Long id, Long userId) {
        ReturnObject<Order> res = orderDao.getOrder(id);
        if (res.getData() == null) return res;
        Order order = res.getData();
        if (!Objects.equals(order.getCustomerId(), userId)) return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        String documentId = order.getOrderSn();
        InternalReturnObject<List<RefundRetVo>> paymentRetVoInternalReturnObject = payService.getRefundByDocumentId(documentId);
        if (paymentRetVoInternalReturnObject.getData() == null)
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该退款单不存在");
        return new ReturnObject(paymentRetVoInternalReturnObject.getData());
    }

    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderItemById(Long id) {
        ReturnObject<OrderItem> orderItemReturnObject = orderDao.getOrderItemById(id);
        if (orderItemReturnObject.getData() == null) return orderItemReturnObject;
        return new ReturnObject(cloneVo(orderItemReturnObject.getData(), OrderItemRetVo.class));
    }

    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderDetailByOrderSn(String orderSn) {
        ReturnObject orderPoRet = orderDao.getOrderByOrderSn(orderSn);
        if (orderPoRet.getCode() != OK)
            return orderPoRet;
        OrderPo orderPo = (OrderPo) orderPoRet.getData();

        ReturnObject orderItemsRet = orderDao.getOrderItemsByOrderId(orderPo.getId());
        if (orderItemsRet.getCode() != OK)
            return orderItemsRet;
        List<OrderItemPo> pos = (List<OrderItemPo>) orderItemsRet.getData();
        ReturnObject listRet = getListRetVo(new ReturnObject<>(pos), OrderItemRetVo.class);
        List<OrderItemRetVo> retVos = (List<OrderItemRetVo>) listRet.getData();

        SimpleOrderRetVo simpleOrderRetVo = cloneVo(orderPo, SimpleOrderRetVo.class);
        simpleOrderRetVo.setOrderItems(retVos);
        return new ReturnObject<>(simpleOrderRetVo);
    }
}
